package org.sdnstproject.interlayer.OF13Protocal;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;

import org.projectfloodlight.openflow.types.U32;
import org.sdnstproject.interlayer.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class FuPacketOut {
	private static final Logger log = LoggerFactory.getLogger(FuPacketOut.class);
    public byte version = (byte)4;
    public byte type = (byte)13;
    public short length = (short)82;//MINIMUM_LENGTH = 24
    public long xid = 0x0L;//需要dummyswitch设置
    public int bufferId = 0xffff;
    public int inPort = 1;
    public short actionLen = (short)16;//16
    public short pad1;//6 bytes pad
    public int pad2;
    public byte[] action = Utils.hexStringToByteArray("0000000100000002ffff000000000000");
    public byte[] data = Utils.hexStringToByteArray("9a089f9ea6300ae8bf550be5080600010800060400020ae8bf550be50a0000019a089f9ea6300a000002");
	
	public FuPacketOut() {
		
	}
	    	
    public FuPacketOut setField(String field, String value) {
		switch (field) {
		case "version":
			this.version = Byte.parseByte(value);
			break;
		case "type":
			this.type = Byte.parseByte(value);
			break;
		case "length":
			this.length = Short.parseShort(value);
			break;
		case "xid":
			this.xid = Long.parseLong(value);
			break;
		case "bufferId":
			this.bufferId = Integer.parseInt(value);
			break;
		case "inPort":
			this.inPort = Integer.parseInt(value);
			break;
		case "actionLen":
			this.actionLen = Short.parseShort(value);
			break;
		case "action":
			this.action = new byte[actionLen];
			new Random().nextBytes(action);
			break;
		case "data":
			this.data = new byte[new Random().nextInt(40)+40];
			new Random().nextBytes(data);
			break;
		}
		return this;
	}
    
    
	public ByteBuf writeTo() {
		ByteBuf bb = Unpooled.directBuffer();
        int startIndex = bb.writerIndex();
        // fixed value property version = 4
        bb.writeByte(version);
        // fixed value property type = 3
        bb.writeByte(type);
        // length is length of variable message, will be updated at the end
        int lengthIndex = bb.writerIndex();
        bb.writeShort(length);

        bb.writeInt(U32.t(xid));
        bb.writeInt(bufferId);
        bb.writeInt(inPort);
        int actionsLenIndex = bb.writerIndex();
        bb.writeShort(actionLen);
        bb.writeShort(pad1);
        bb.writeInt(pad2);
        int actionsStartIndex = bb.writerIndex();
        bb.writeBytes(action);
        int actionsLength = bb.writerIndex() - actionsStartIndex;
        bb.setShort(actionsLenIndex, actionsLength);
        bb.writeBytes(data);
        // update length field
        length = (short)(bb.writerIndex() - startIndex);
        bb.setShort(lengthIndex, length);
        return bb;
    }
	
	@Override
    public String toString() {
        StringBuilder b = new StringBuilder("FuPacketOutVer13(");
        b.append("version=").append(version);
        b.append(", ");
        b.append("type=").append(type);
        b.append(", ");
        b.append("length=").append(length);
        b.append(", ");
        b.append("xid=").append(xid);
        b.append(", ");
        b.append("bufferId=").append(bufferId);
        b.append(")");
        b.append("inPort=").append(inPort);
        b.append(")");
        b.append("actionLen=").append(actionLen);
        b.append(")");
        b.append("action=").append(Arrays.toString(action));
        b.append(")");
        b.append("data=").append(Arrays.toString(data));
        b.append(")");
        return b.toString();
    }
}
